Almost pairs trading

Almost pairs trading#

This little exercise goes back to an idea by Stephen Boyd:

The simulator should always be completely agnostic as to the trading policy. You should even demonstrate this with silly policies. Like here’s one: Each day choose names from the universe at random. Buy one (say 0.1 of your portfolio wealth) and short one the same amount. Not a good strategy, but a valid one. Of course the simulate will terminate if you go bust (which seems likely).

import numpy as np
import pandas as pd
from loguru import logger

from cvx.simulator import Builder

pd.options.plotting.backend = "plotly"
logger.info("Load prices")
prices = pd.read_csv("data/stock-prices.csv", index_col=0, parse_dates=True, header=0)

logger.info("Build portfolio")
b = Builder(prices=prices, initial_aum=1e6)

for t, state in b:
    assert state.nav > 0, "Game over"
    
    # pick two assets at random
    pair = np.random.choice(state.assets, 2, replace=False)
    
    # compute the pair
    units = pd.Series(index=state.assets, data=0.0)
    units[pair] = [state.nav, -state.nav] / state.prices[pair].values    
    b.position = 0.1*units

    # 1 bps of the traded volume (measured in USD) are paid as fee
    costs = 0.0001 * (state.trades.abs() * state.prices).sum()
    b.aum = state.aum - costs
    

portfolio = b.build()
2024-10-01 20:26:19.861 | INFO     | __main__:<module>:1 - Load prices
2024-10-01 20:26:19.880 | INFO     | __main__:<module>:4 - Build portfolio
portfolio = b.build()
portfolio.nav.plot()